﻿using System;
using GeoAPI.Geometries;

namespace NetTopologySuite.LinearReferencing
{
	public class LinearIterator
	{
		public static int SegmentEndVertexIndex(LinearLocation loc)
		{
			if (loc.SegmentFraction > 0.0)
			{
				return loc.SegmentIndex + 1;
			}
			return loc.SegmentIndex;
		}

		public LinearIterator(IGeometry linearGeom) : this(linearGeom, 0, 0)
		{
		}

		public LinearIterator(IGeometry linearGeom, LinearLocation start) : this(linearGeom, start.ComponentIndex, LinearIterator.SegmentEndVertexIndex(start))
		{
		}

		public LinearIterator(IGeometry linearGeom, int componentIndex, int vertexIndex)
		{
			if (!(linearGeom is ILineal))
			{
				throw new ArgumentException("Lineal geometry is required.");
			}
			this._linearGeom = linearGeom;
			this._numLines = linearGeom.NumGeometries;
			this._componentIndex = componentIndex;
			this._vertexIndex = vertexIndex;
			this.LoadCurrentLine();
		}

		private void LoadCurrentLine()
		{
			if (this._componentIndex >= this._numLines)
			{
				this._currentLine = null;
				return;
			}
			this._currentLine = (ILineString)this._linearGeom.GetGeometryN(this._componentIndex);
		}

		public bool HasNext()
		{
			return this._componentIndex < this._numLines && (this._componentIndex != this._numLines - 1 || this._vertexIndex < this._currentLine.NumPoints);
		}

		public void Next()
		{
			if (!this.HasNext())
			{
				return;
			}
			this._vertexIndex++;
			if (this._vertexIndex >= this._currentLine.NumPoints)
			{
				this._componentIndex++;
				this.LoadCurrentLine();
				this._vertexIndex = 0;
			}
		}

		public bool IsEndOfLine
		{
			get
			{
				return this._componentIndex < this._numLines && this._vertexIndex >= this._currentLine.NumPoints - 1;
			}
		}

		public int ComponentIndex
		{
			get
			{
				return this._componentIndex;
			}
		}

		public int VertexIndex
		{
			get
			{
				return this._vertexIndex;
			}
		}

		public ILineString Line
		{
			get
			{
				return this._currentLine;
			}
		}

		public Coordinate SegmentStart
		{
			get
			{
				return this._currentLine.GetCoordinateN(this._vertexIndex);
			}
		}

		public Coordinate SegmentEnd
		{
			get
			{
				if (this._vertexIndex < this.Line.NumPoints - 1)
				{
					return this._currentLine.GetCoordinateN(this._vertexIndex + 1);
				}
				return null;
			}
		}

		private readonly IGeometry _linearGeom;

		private readonly int _numLines;

		private ILineString _currentLine;

		private int _componentIndex;

		private int _vertexIndex;
	}
}
